import numpy as np

class GPR:
    def __init__(self, kernel='rbf', lengthscale=1.0, noise=1e-6):
        self.kernel = kernel
        self.lengthscale = lengthscale
        self.noise = noise

    def _rbf_kernel(self, X1, X2):
        sqdist = np.sum(X1**2,1).reshape(-1,1) + np.sum(X2**2,1) - 2*np.dot(X1, X2.T)
        return np.exp(-0.5 / self.lengthscale**2 * sqdist)

    def fit(self, X, y):
        self.X_train = X
        self.y_train = y
        K = self._rbf_kernel(X, X) + self.noise * np.eye(len(X))
        self.L = np.linalg.cholesky(K)
        self.alpha = np.linalg.solve(self.L.T, np.linalg.solve(self.L, y))

    def predict(self, X):
        K_s = self._rbf_kernel(X, self.X_train)
        return K_s @ self.alpha 